// File: package general.DebugLog
// Author: rlb (though I'm not proud of it) and CSA students
// Progress: ongoing
// TODO: add GUI and file logs
// Desc: DebugLog is a stand-in for generic debugging utilities, especially
// useful in the absence of an integrated debugger. All members are static
// - less flexible but easier to use.
// To use, import and have at it.

package gfs;
import java.util.Scanner;


public class DebugLog
    {
    public static void Log(String tag)
    // puts a line of text to the log(s)
    // String: any text; each call to Log creates a new line
        {
        System.out.println(tag);
        }
    public static void Log(String tag, String mod, int line)
    // Helper function: puts a line of text including TLU name/line #
    // String tag: the message to log
    // String mod: the name of the module
    // int line: the line in the TLU
    // Desc: this method is used directly by the Assert methods
        {
        String out= new String(tag);
        if (mod.length() > 0)
            out += "\n     In module: " + mod;
        if (line > 0)
            out += "  at line: " + line;
        DebugLog.Log(out);
        }

    public static boolean Assert(boolean exp, String tag)
    // Tests an assertion, puts a custom message to the log if false
    // Returns: the logical value of the condition to assert
    // boolean: the value - condition to test
    // Desc: function allows logging for condtion tests including
    // module and line number where assertion logged. Does not
    // require special compilation/runtime flag (-ea)
    //  NOTE: thisAssert does NOT stop execution
        {
        // Note that this is hazardous as we assume that the call here is
        // only one frame away (accessing element 1 in stack trace)
        if (!exp)
            {
            String msg = new String("Assertion failed:" + tag);
            Throwable temp = new Throwable();
            DebugLog.Log(msg, temp.getStackTrace()[1].getFileName(),
                              temp.getStackTrace()[1].getLineNumber());
            }
        return exp;
        }

    public static boolean Assert(boolean exp)
    // Tests an assertion, puts a generic message to the log if false
    // Returns: the logical value of the condition to assert
    // boolean: the value
    // Desc: function allows logging for condtion tests including
    // module and line number where assertion logged. Does not
    // require special compilation/runtime flag (-ea)
    //  NOTE: thisAssert does NOT stop execution
        {
        // Note that this is hazardous as we assume that the call here is
        // only one frame away (accessing element 1 in stack trace)
        if (!exp)
            {
            String msg = new String("Assertion failed: no message");
            Throwable temp = new Throwable();
            DebugLog.Log(msg, temp.getStackTrace()[1].getFileName(),
                              temp.getStackTrace()[1].getLineNumber());
            }
        return exp;
        }

    public static boolean AssertAndThrow(boolean exp, String tag)
    // Tests an assertion, puts a custom message to the log
    // and throws - this works much like java's assert
    // Returns: the logical value of the condition to assert - included
    //  only for consistency
    // boolean: the value - condition to test
    // Desc: function allows logging for condtion tests including
    // module and line number where assertion logged. Does not
    // require special compilation/runtime flag (-ea)
    //  NOTE: AssertAndThrow throws a RuntimeException instance
        {
        if (!Assert(exp, tag)) // pass to non-halting form
            {
            RuntimeException temp = new RuntimeException(tag);
            DebugLog.Log(tag, temp.getStackTrace()[1].getFileName(),
                            temp.getStackTrace()[1].getLineNumber());
            throw temp;
            }
        return exp;
        }

    public static void pause(String msg)
    // uses simple I/O from stdin to 'hold' processing; to continue
    // the thread, type enter
    // String: a message to display
        {
        System.out.println(msg);
        pause();
        }

    public static void pause()
    // uses simple I/O from stdin to 'hold' processing; to continue
    // the thread, type enter
        {
        System.out.println("   >>> DebugLog paused: Enter to continue: ");
        input.nextLine();
        }

    public static void location()
    // Reports to the log the TLU and line number at point of call
        {
        Throwable temp = new Throwable();
        DebugLog.Log("   LOC: ", temp.getStackTrace()[1].getFileName(),
                               temp.getStackTrace()[1].getLineNumber());
        }
	// the following array report functions are courtesy of Joel Jauregui
    public static void dumpIntArray(int[] array)
        {
        Log("Dump array of " + array.length + " integers.\r\n");
        Log(arrayToString(array));
        }
    public static void dumpLongArray(long[] array)
        {
        Log("Dump array of " + array.length + " longs.\r\n");
        Log(arrayToString(array));
        }
    public static void dumpDoubleArray(double[] array)
        {
        Log("Dump array of " + array.length + " doubles.");
        Log(arrayToString(array));
        }
    public static void dumpCharArray(char[] array)
        {
        Log("Dump array of " + array.length + " characters.");
        Log(arrayToString(array));
        }
    public static void dumpString(String[] array, String spacer)
        {
        Log("Dump array of " + array.length + " strings.");
        Log(arrayToString(array, spacer));
        }
    public static String arrayToString(int[] array)
        {
        int counter = 0;
        StringBuffer out = new StringBuffer();
        while(counter < array.length)
            {
            out.append(" element " + counter + " is " + array[counter++]);
            }
        return out.toString();
        }
    public static String arrayToString(long[] array)
        {
        int counter = 0;
        StringBuffer out = new StringBuffer();
        while(counter < array.length)
            {
            out.append(" element " + counter + " is " + array[counter++]);
            }
        return out.toString();
        }
    public static String arrayToString(double[] array)
        {
        int counter = 0;
        StringBuffer out = new StringBuffer();
        while(counter < array.length)
            {
            out.append(" element " + counter + " is " + array[counter++]);
            }
        return out.toString();
        }
    public static String arrayToString(char[] array)
        {
        int counter = 0;
        StringBuffer out = new StringBuffer();
        while(counter < array.length)
            {
            out.append(" element " + counter + " is " + array[counter++]);
            }
        return out.toString();
        }
    public static String arrayToString(String[] array, String spacer)
        {
        int counter = 0;
        StringBuffer out = new StringBuffer();
        while(counter < array.length)
            out.append(" " + array[counter++] + spacer);
        return out.toString();
        }


    private DebugLog ()
        {
        }





    // DATA MEMBERS
    private static Scanner input = new Scanner(System.in);

/*
Do this: to 'turn off' the methods one would construct this
guy with a flag (boolean); compile w/ false and hope for code
removal - this could still cause a function call
    public static DebugLog DEBUG_LOG;
    static
        {
        DebugLog DEBUG_LOG = new DebugLog();
        }
*/
    } // class DebugLog
